home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2002 November / SGI Freeware 2002 November - Disc 1.iso / dist / fw_exmh.idb / usr / freeware / lib / exmh-2.5 / ftoc.tcl.z / ftoc.tcl
Text File  |  2002-07-08  |  36KB  |  1,365 lines

  1. # ftoc.tcl
  2. #
  3. # Folder table of contents display.
  4. #
  5. # Copyright (c) 1993 Xerox Corporation.
  6. # Use and copying of this software and preparation of derivative works based
  7. # upon this software are permitted. Any distribution of this software or
  8. # derivative works must comply with all applicable United States export
  9. # control laws. This software is made available AS IS, and Xerox Corporation
  10. # makes no warranty about the software, its performance or its conformity to
  11. # any specification.
  12.  
  13. proc Ftoc_Init {} {
  14.     global ftoc
  15.     set ftoc(displayValid) 0        ;# 1 => pick results, not full scan
  16.     set ftoc(displayDirty) 0        ;# 1 => display differs from cache
  17.     set ftoc(mono) [expr {[winfo depth .] <= 4}]
  18.     # Parameters to the Next button
  19.     Preferences_Add "Scan Listing" \
  20. "These settings affect the behavior of Exmh as you move through the scan listing to view and mark messages.
  21. While the default for Auto Commit is OFF, I suggest you try it out.
  22. Messages are still temporarily marked, but the commit is done when you need it." {
  23.     {exwin(ftextLines)    ftextLines 15    {Scan listing lines}
  24. "Lines in the Scan listing window, which is
  25. also called Folder-Table-Of-Contents (FTOC)."}
  26.     {ftoc(implied) impliedDirection ON "Implied Direction"
  27. "If set, Exmh will remember your current direction,
  28. next or previous, and go that way after you mark a
  29. message for deletion or refiling."}
  30.     {ftoc(nextGuard) nextGuard OFF "Next Guard"
  31. "If set, Exmh will warn you that you are about to
  32. change folders when you hit Next.  This means you
  33. end up hitting Next twice to chain the to next
  34. folder with unseen messages."}
  35.     {ftoc(autoCommit) autoCommit OFF "Auto Commit"
  36. "If set, Exmh will invoke the Commit operation to
  37. commit deletions and refiles when it would otherwise
  38. just complain that such a commit is required."}
  39.     {ftoc(commitDialog) commitDialog ON "Commit Dialog"
  40. "If set, you get a confirmation dialog when exmh wants
  41. you to commit pending changes.  Otherwise you just
  42. get a warning message and have to hit the Commit button."}
  43.     {ftoc(autoPack) autoPack OFF "Auto Pack"
  44. "If set, Exmh will pack the folder every time a commit is performed."}
  45.     {ftoc(autoSort) autoSort OFF "Auto Sort"
  46. "If set, Exmh will sort the folder every time you change into it"}
  47.     {ftoc(autoSortType) autoSortType {CHOICE date subject sender custom} {Sorting criterion}
  48. "Sort by Date:/Subject:/From: or user-defined fields. Uses MH sortm command."}
  49.     {ftoc(autoSortCrit) autoSortCrit {-textfield keywords} {Custom criterion}
  50. "Custom parameters for sortm"}
  51.     {ftoc(showNew) ftocShowNew OFF "Show New Messages"
  52. "If set, Exmh will scroll the FTOC display to show
  53. new message that arrive because of an Inc."}
  54.     {ftoc(linkAdvance) advanceOnLink OFF "Advance after Link"
  55. "If set, Exmh will advance to the next message after a link."}
  56.     {ftoc(skipMarked) skipMarked ON "Next/Prev skip marked msgs"
  57. "If set, Next and Prev will skip over messages that have
  58. been marked for move or delete."}
  59.     {flist(cycleBack)    cycleBack ON    "Cycle back to first"
  60. "If there are no folders with unseen messages, then this
  61. option causes you to change to the first folder given by your
  62. Folder-Order MH profile entry."}
  63.     {ftoc(scanWidth) scanWidth 100 "Default scan width"
  64. "This value is passed as the -width argument to scan and in."}
  65.     {ftoc(scanSize) scanSize 100 "Default amount to scan"
  66. "Only the last N messages are scanned when you first enter a folder.
  67. The number is controlled by this setting."}
  68.     }
  69. }
  70. proc Ftoc_Reset { numMsgs msgid folder } {
  71.     global ftoc exwin
  72.     Exmh_Debug Ftoc_Reset $folder has $numMsgs msgs
  73.     set ftoc(numMsgs) $numMsgs        ;# num msgs in the scan listing
  74.     set ftoc(changed) 0            ;# Number of moves/deletes marked
  75.     set ftoc(lineset) {}        ;# set of selected messages
  76.     set ftoc(pickone) 1            ;# lineset is empty
  77.     set ftoc(folder) $folder        ;# Currently displayed folder
  78.     set ftoc(direction) next        ;# assumed next direction
  79.     set ftoc(softChange) [expr {! $ftoc(nextGuard)}]
  80.     set ftoc(lasthit) {}        ;# search anchor
  81.     if {$msgid == {}} {
  82.     set ftoc(curLine) {}        ;# current display line number
  83.     } else {
  84.     set ftoc(curLine) {}        ;# Set later in Msg_Change ?
  85.     }
  86. }
  87. proc Ftoc_Update { numMsgs folder } {
  88.     # Update size of message list after inc'ing into current folder
  89.     global ftoc
  90.     Exmh_Debug Ftoc_Update $folder has $numMsgs msgs
  91.     set ftoc(numMsgs) $numMsgs
  92. }
  93.  
  94. proc Ftoc_Bindings { w } {
  95.     # Bindings for the ftoc text widget
  96.  
  97.     # The TScroll binding to too general.
  98.     # We'll do our own scroll bindings here.
  99.     bindtags $w [list $w]
  100.  
  101.     # Button-1 starts selection range
  102.     bind $w <Button-1> {
  103.     FtocRangeStart [lindex [split [%W index current] .] 0]
  104.     Exmh_Focus
  105.     }
  106.     bind $w <Shift-Button-1> {
  107.     FtocRangeAdd [lindex [split [%W index current] .] 0]
  108.     Exmh_Focus
  109.     }
  110.     bind $w <B1-Motion> {
  111.     FtocRangeExtendXY %x %y
  112.     }
  113.     bind $w <Shift-B1-Motion> {
  114.     FtocRangeExtendXY %x %y
  115.     }
  116.     bind $w <Any-ButtonRelease-1> {
  117.     FtocRangeEnd [lindex [split [%W index current] .] 0] 0
  118.     }
  119.     bind $w <Shift-ButtonRelease-1> {
  120.     FtocRangeEnd [lindex [split [%W index current] .] 0] 1
  121.     }
  122.     bind $w <Button-3> {
  123.     set lineNumber [lindex [split [%W index current] .] 0]
  124.     Msg_Pick $lineNumber noshow
  125.     Exmh_Focus
  126.     }
  127.     bind $w <Double-Button-1> { }
  128.     bind $w <Triple-Button-1> { }
  129.  
  130.     bind $w <Button-2> {WidgetTextMark %W %y}
  131.     bind $w <B2-Motion> {WidgetTextDragto %W %y $exwin(scrollSpeed)}
  132.  
  133.     Drag_Attach $w FtocDragSelect Shift 3
  134. }
  135. proc FtocRangeStart { line } {
  136.     # For normal button-down "start a selection"
  137.     global ftoc
  138.     Ftoc_RangeUnHighlight
  139.     set ftoc(pickstart) $line
  140.     set ftoc(pickend) $line
  141.     set ftoc(pickstate) new
  142.     set ftoc(extend) 0
  143.     Ftoc_RangeHighlight $line $line
  144. }
  145. proc FtocRangeAdd { line } {
  146.     # For shift-select "add to selection"
  147.     global ftoc
  148.     set ftoc(pickstart) $line
  149.     set ftoc(pickend) $line
  150.     set ftoc(pickstate) invert
  151.     set ftoc(extend) 0
  152.     FtocRangeInvert $line $line
  153. }
  154. proc FtocRangeEnd { {line {}} {addcurrent 0} } {
  155.     # For end of button sweep
  156.     global ftoc exwin
  157.     catch {unset ftoc(extend)}
  158.     if ![info exists ftoc(pickend)] {
  159.     # Spurious button-release event
  160.     return
  161.     }
  162.     if {($line == $ftoc(pickstart)) && !$addcurrent} {
  163.     # regular button click optimization
  164.     unset ftoc(pickend)
  165.     Msg_Pick $line show
  166.     return
  167.     }
  168.     if {$line != {}} {
  169.     FtocRangeExtend $line
  170.     }
  171.     FtocPickRange $addcurrent
  172.     catch {unset ftoc(pickend)}
  173. }
  174. proc Ftoc_PickMsgs { ids addtosel } {
  175.     # For adding to the selection by message number
  176.     global ftoc
  177.     Exmh_Status "Marking [llength $ids] hits"
  178.     set lines {}
  179.     for {set L 0} {$L <= $ftoc(numMsgs)} {incr L} {
  180.     set ix [lsearch $ids [Ftoc_MsgNumber $L]]
  181.     if {$ix >= 0} {
  182.         lappend lines $L
  183.         set ids [lreplace $ids $ix $ix]
  184.         if {[string length $ids] == 0} {
  185.         break
  186.         }
  187.     }
  188.     }
  189.     Ftoc_LinesHighlight $lines
  190.     FtocPickRange $addtosel
  191. }
  192. proc FtocRangeExtendXY { x y } {
  193.     global ftoc exwin widgetText
  194.  
  195.     if ![info exists ftoc(extend)] {
  196.     return
  197.     }
  198.     set active $ftoc(extend)
  199.  
  200.     set h [winfo height $exwin(ftext)]
  201.     if {$y > $h} {
  202.     set ftoc(extend) [expr $y-$h]
  203.     } else {
  204.     if {$y < 0} {
  205.         set ftoc(extend) $y
  206.     } else {
  207.         set ftoc(extend) 0
  208.     }
  209.     }
  210.     
  211.     if {$ftoc(extend) == 0} {
  212.     FtocRangeExtend [lindex [split [$exwin(ftext) index @$x,$y] .] 0]
  213.     } else {
  214.     if {! $active} {
  215.         set ftoc(lastmark) [lindex [ split [$exwin(ftext) index @$x,$y] .] 0]
  216.         after $widgetText(selectDelay) [list FtocSelExtend]
  217.     }
  218.     }
  219. }
  220. proc FtocSelExtend {} {
  221.     global ftoc exwin widgetText
  222.     set w $exwin(ftext)
  223.     if {![info exists ftoc(extend)] ||
  224.     ($ftoc(extend) == 0)} {
  225.     return
  226.     }
  227.     catch {
  228.     set delta [expr {$ftoc(extend) / 16}]
  229.     if {$delta == 0} {
  230.         set delta [expr { ($ftoc(extend) < 0) ? -1 : 1 }]
  231.     }
  232.     set newmark [expr {$ftoc(lastmark) + $delta}]
  233.     FtocRangeExtend $newmark
  234.     set ftoc(lastmark) $newmark
  235.     $w yview -pickplace $newmark.0
  236.     after $widgetText(selectDelay) [list FtocSelExtend]
  237.     }
  238. }
  239. proc FtocRangeExtend { line } {
  240.     global ftoc
  241.     if ![info exists ftoc(pickend)] {
  242.     return
  243.     }
  244.     if {$line <= 0} {
  245.     set line 1
  246.     }
  247.     if {$line > $ftoc(numMsgs)} {
  248.     set line $ftoc(numMsgs)
  249.     }
  250.     if {$line == $ftoc(pickend)} {
  251.     # Invariant, previously defined selection is fine.
  252.     return
  253.     }
  254.     if {$line == 0} {
  255.     # no messages in folder
  256.     return
  257.     }
  258.     if {$ftoc(pickstate) != "invert"} {
  259.     if {$ftoc(pickstart) < $ftoc(pickend)} {
  260.         # Growing downward
  261.         if {$line > $ftoc(pickend)} {
  262.         Ftoc_RangeHighlight [expr $ftoc(pickend)+1] $line
  263.         } else {
  264.         if {$line < $ftoc(pickstart)} {
  265.             if {$ftoc(pickstart) != $ftoc(pickend)} {
  266.             # Change direction
  267.             FtocRangeClear [expr $ftoc(pickstart)+1] \
  268.                     $ftoc(pickend)
  269.             }
  270.             Ftoc_RangeHighlight [expr $ftoc(pickstart)-1] $line
  271.         } else {
  272.             # Shrink selection
  273.             FtocRangeClear [expr $line+1] $ftoc(pickend)
  274.         }
  275.         }
  276.     } else {
  277.         # Growing upward
  278.         if {$line < $ftoc(pickend)} {
  279.         Ftoc_RangeHighlight [expr $ftoc(pickend)-1] $line
  280.         } else {
  281.         if {$line > $ftoc(pickstart)} {
  282.             if {$ftoc(pickstart) != $ftoc(pickend)} {
  283.             # Change direction
  284.             FtocRangeClear [expr $ftoc(pickstart)-1] \
  285.                     $ftoc(pickend)
  286.             }
  287.             Ftoc_RangeHighlight [expr $ftoc(pickstart)+1] $line
  288.         } else {
  289.             # Shrink selection
  290.             FtocRangeClear [expr $line-1] $ftoc(pickend)
  291.         }
  292.         }
  293.     }
  294.     } else {
  295.     if {$ftoc(pickstart) < $ftoc(pickend)} {
  296.         # Growing downward
  297.         if {$line > $ftoc(pickend)} {
  298.         FtocRangeInvert [expr $ftoc(pickend)+1] $line
  299.         } else {
  300.         if {$line < $ftoc(pickstart)} {
  301.             if {$ftoc(pickstart) != $ftoc(pickend)} {
  302.             # Change direction
  303.             FtocRangeInvert [expr $ftoc(pickstart)+1] \
  304.                     $ftoc(pickend)
  305.             }
  306.             FtocRangeInvert [expr $ftoc(pickstart)-1] $line
  307.         } else {
  308.             # Shrink selection
  309.             FtocRangeInvert [expr $line+1] $ftoc(pickend)
  310.         }
  311.         }
  312.     } else {
  313.         # Growing upward
  314.         if {$line < $ftoc(pickend)} {
  315.         FtocRangeInvert [expr $ftoc(pickend)-1] $line
  316.         } else {
  317.         if {$line > $ftoc(pickstart)} {
  318.             if {$ftoc(pickstart) != $ftoc(pickend)} {
  319.             # Change direction
  320.             FtocRangeInvert [expr $ftoc(pickstart)-1] \
  321.                     $ftoc(pickend)
  322.             }
  323.             FtocRangeInvert [expr $ftoc(pickstart)+1] $line
  324.         } else {
  325.             # Shrink selection
  326.             FtocRangeInvert [expr $line-1] $ftoc(pickend)
  327.         }
  328.         }
  329.     }
  330.     }
  331.     set ftoc(pickend) $line
  332. }
  333. proc FtocRangeInvert { start end } {
  334.     global exwin
  335.     set win $exwin(ftext)
  336.     if {$start > $end} {
  337.     set tmp $start ; set start $end ; set end $tmp
  338.     }
  339.     for {set line $start} {$line <= $end} {incr line} {
  340.     catch {
  341.         set newtag range
  342.         set oldtag {}
  343.         set nuke 0
  344.         foreach tag [$win tag names $line.0] {
  345.         case $tag {
  346.             deleted { set newtag drange ; set oldtag $tag ; break; }
  347.             moved { set newtag mrange ; set oldtag $tag ; break; }
  348.             range { set newtag {} ; set oldtag $tag ; break; }
  349.             drange { set newtag deleted ; set oldtag $tag ;
  350.                 set nuke 1; break}
  351.             mrange { set newtag moved ; set oldtag $tag ;
  352.                 set nuke 1; break; }
  353.         }
  354.         }
  355.         if {$nuke} {
  356.         set ix [lsearch $ftoc(lineset) $line]
  357.         if {$ix >= 0} {
  358.             set ftoc(lineset) [lreplace $ftoc(lineset) $ix $ix]
  359.         }
  360.         }
  361.         if {$oldtag != {}} {
  362.         $win tag remove $oldtag $line.0 $line.end
  363.         }
  364.         if {$newtag != {}} {
  365.         $win tag add $newtag $line.0 $line.end
  366.         }
  367.     }
  368.     }
  369. }
  370. proc Ftoc_RangeHighlight { start end } {
  371.     global exwin
  372.     set win $exwin(ftext)
  373.     if {$start > $end} {
  374.     set tmp $start ; set start $end ; set end $tmp
  375.     }
  376.     for {set line $start} {$line <= $end} {incr line} {
  377.     set newtag range
  378.     foreach tag [$win tag names $line.0] {
  379.         case $tag {
  380.         {drange deleted} { set newtag drange ;  break; }
  381.         {mrange moved} { set newtag mrange ;  break; }
  382.         }
  383.     }
  384.     $win tag add $newtag $line.0 $line.end
  385.     }
  386. }
  387. proc Ftoc_LinesHighlight { lines } {
  388.     global exwin
  389.     set win $exwin(ftext)
  390.     if {$lines == {}} {
  391.     return
  392.     }
  393.     WidgetTextYview $exwin(ftext) -pickplace [lindex $lines 0].0
  394.     update idletasks
  395.     foreach line $lines {
  396.     set newtag range
  397.     foreach tag [$win tag names $line.0] {
  398.         case $tag {
  399.         {drange deleted} { set newtag drange ;  break; }
  400.         {mrange moved} { set newtag mrange ;  break; }
  401.         }
  402.     }
  403.     $win tag add $newtag $line.0 $line.end
  404.     }
  405. }
  406. proc FtocRangeClear { start end } {
  407.     global exwin
  408.     set win $exwin(ftext)
  409.     if {$start > $end} {
  410.     set tmp $start ; set start $end ; set end $tmp
  411.     }
  412.     for {set line $start} {$line <= $end} {incr line} {
  413.     catch {
  414.         set newtag {}
  415.         set oldtag range
  416.         foreach tag [$win tag names $line.0] {
  417.         case $tag {
  418.             drange { set newtag deleted ; set oldtag drange; break; }
  419.             mrange { set newtag moved ; set oldtag mrange; break; }
  420.             range { break }
  421.         }
  422.         }
  423.         $win tag remove $oldtag $line.0 $line.end
  424.         if {$newtag != {}} {
  425.         $win tag add $newtag $line.0 $line.end
  426.         }
  427.     }
  428.     }
  429. }
  430. proc Ftoc_RangeUnHighlight { } {
  431.     global exwin
  432.     set win $exwin(ftext)
  433.     foreach tag {range drange mrange} {
  434.     foreach range [FtocMakePairs [$win tag ranges $tag]] {
  435.         eval $win tag remove $tag $range
  436.         if {$tag == "drange"} {
  437.         eval $win tag add deleted $range
  438.         }
  439.         if {$tag == "mrange"} {
  440.         eval $win tag add moved $range
  441.         }
  442.     }
  443.     }
  444. }
  445.  
  446. # For user programming
  447. proc Ftoc_BindDouble { cmd } {
  448.     global exwin
  449.     bind $exwin(ftext) <Double-1> $cmd
  450. }
  451. proc Ftoc_BindRight { cmd } {
  452.     global exwin
  453.     bind $exwin(ftext) <3> $cmd
  454. }
  455.  
  456. proc Ftoc_FindMsg { msgid {line {}} } {
  457.     global ftoc
  458.     if {$line != {}} {
  459.     switch -glob -- $line {
  460.         first  {return 1}
  461.         last   {return $ftoc(numMsgs)}
  462.         [0-9]* {
  463.         if {$line > $ftoc(numMsgs)} {
  464.             return $ftoc(numMsgs)
  465.         } else {
  466.             return $line
  467.         }
  468.         }
  469.         default {return {}}
  470.     }
  471.     }
  472.     if {$msgid == {}} {
  473.     return {}
  474.     }
  475. #
  476. # Linear search for pick and thread FTOCs (pseudo-displays)
  477. #
  478.     if !$ftoc(displayValid) {
  479.         for {set L 1} {$L <= $ftoc(numMsgs)} {incr L} {
  480.             if {[Ftoc_MsgNumber $L] == $msgid} {
  481.                 return $L
  482.             }
  483.         }
  484.         return {}
  485.     }
  486.  
  487.     set min 1
  488.     set max $ftoc(numMsgs)    ;# Ignore trailing blank line
  489.     while (1) {
  490.     set m1 [Ftoc_MsgNumber $min]
  491.     if {$msgid == $m1} {
  492.         return $min
  493.     }
  494.     set m2 [Ftoc_MsgNumber $max]
  495.     if {$msgid == $m2} {
  496.         return $max
  497.     }
  498.     if {$msgid > $m2 || $msgid < $m1} {
  499.         Exmh_Status "Cannot find $msgid ($m1,$m2)" warn
  500.         return "" ;# new message not listed
  501.     }
  502.     if {$max == $min} {
  503.         return ""    ;# not found
  504.     }
  505.     set next [expr int(($max+$min)/2)]
  506.     set m3 [Ftoc_MsgNumber $next]
  507.     if {$m3 > $msgid} {
  508.         set max $next
  509.     } elseif {$min == $next} {
  510.         Exmh_Status "Cannot find $msgid" warn
  511.         return "" ;# new message not listed
  512.     } else {
  513.         set min $next
  514.     }
  515.     }
  516.     # not reached
  517. }
  518. proc Ftoc_MsgNumber { L } {
  519.     global exwin
  520.     if [catch {$exwin(ftext) get $L.0 $L.end} line] {
  521.     return ""
  522.     }
  523.     return [Ftoc_MsgNumberRaw $line]
  524. }
  525. proc Ftoc_MsgNumberRaw { line } {
  526.     if [regexp {( *)([0-9]+)} $line foo foo2 number] {
  527.     return $number
  528.     } else {
  529.     return ""
  530.     }
  531. }
  532. proc FtocPickRange { {addcurrent 0} } {
  533.     # Select a range of messages, or add to the current range
  534.     # Because of toggle/inverted selections, we pretty much
  535.     # have to recompute the select set from range tags
  536.     global exwin ftoc
  537.     set lineset {}
  538.     if {$ftoc(curLine) != {}} {
  539.     if {$addcurrent} {
  540.         Ftoc_RangeHighlight $ftoc(curLine) $ftoc(curLine)
  541.     }
  542.     Ftoc_ClearCurrent
  543.     Msg_ClearCurrent
  544.     set ftoc(curLine) {}
  545.     }
  546.     foreach range [concat \
  547.     [FtocMakePairs [$exwin(ftext) tag ranges range]] \
  548.     [FtocMakePairs [$exwin(ftext) tag ranges drange]] \
  549.     [FtocMakePairs [$exwin(ftext) tag ranges mrange]]] {
  550.     set mark1 [lindex $range 0]
  551.     set line [lindex [split $mark1 .] 0]
  552.     lappend lineset $line
  553.     }
  554.     if {$lineset == {}} {
  555.     return            ;# spurious <ButtonRelease-1> events
  556.     }
  557.     set ftoc(lineset) $lineset
  558.     set ftoc(pickone) 0
  559.     if {[llength $ftoc(lineset)] == 1} {
  560.     # This calls Msg_Change,
  561.     # which calls Ftoc_ClearCurrent, which sets pickone to 1,
  562.     # and calls Ftoc_Change, which sets curline
  563.     Msg_Pick [lindex $ftoc(lineset) 0] show
  564.     } else {
  565.     Buttons_Range    ;# Enable actions on ranges
  566.     }
  567. }
  568. proc Ftoc_PickSize {} {
  569.     global ftoc
  570.     set len [llength $ftoc(lineset)]
  571.     if {$len == 0} {
  572.     return [llength $ftoc(curLine)]
  573.     } else {
  574.     return $len
  575.     }
  576. }
  577. proc Ftoc_NewFtoc {} {
  578.     global ftoc
  579.     set ids {}
  580.     foreach l $ftoc(lineset) {
  581.     lappend ids [Ftoc_MsgNumber $l]
  582.     }
  583.     if {[llength $ids] <= 1} {
  584.     Exmh_Status "Select more than one message first" warn
  585.     return
  586.     }
  587.     if {[Ftoc_Changes "new ftoc"] == 0} {
  588.     Exmh_Status $ids
  589.     Scan_ProjectSelection $ids
  590.     }
  591. }
  592.  
  593. # Ftoc_ClearCurrent and Ftoc_Change are two parts of
  594. # dinking the ftoc display when advancing a message.
  595.  
  596. proc Ftoc_ClearCurrent {} {
  597.     # Clear display of current message
  598.     global ftoc exwin
  599.     set ftoc(pickone) 1
  600.     set ftoc(lineset) {}
  601.  
  602.     if {$ftoc(curLine) != {}} {
  603.     $exwin(ftext) tag remove current $ftoc(curLine).0 $ftoc(curLine).end
  604.     $exwin(ftext) tag remove currentBg $ftoc(curLine).0 $ftoc(curLine).end
  605.     Ftoc_RescanLine $ftoc(curLine)
  606.     }
  607.     return $ftoc(curLine)
  608. }
  609. proc Ftoc_Change { msgid line {show show} } {
  610.     global ftoc exwin
  611.     set ftoc(curLine) [Ftoc_FindMsg $msgid $line]
  612.     if {$ftoc(curLine) == {}} {
  613.     set ok 0
  614.     } else {
  615.     if {$show == "show"} {
  616.         $exwin(ftext) tag remove unseen $ftoc(curLine).0 $ftoc(curLine).end
  617.     }
  618.     Ftoc_RescanLine $ftoc(curLine) +
  619.     $exwin(ftext) tag add current $ftoc(curLine).0 $ftoc(curLine).end
  620.     $exwin(ftext) tag add currentBg $ftoc(curLine).0 $ftoc(curLine).end
  621.     set top [$exwin(ftext) index @0,4]
  622.     if [catch {expr {$top+1}}] {set top 0}    ;# trap 100.-1 format, iconic
  623.     if {$ftoc(curLine) == $top ||
  624.         $ftoc(curLine) == $top+$exwin(ftextLines)-1} {
  625.         WidgetTextYview $exwin(ftext) [expr $ftoc(curLine)-$exwin(ftextLines)/2].0
  626.     } else {
  627.         WidgetTextYview $exwin(ftext) -pickplace $ftoc(curLine).0
  628.     }
  629.     set ok 1
  630.     }
  631.     return $ok
  632. }
  633. proc Ftoc_ShowUnseen { folder } {
  634.     global exwin flist
  635.     set unseen [Flist_UnseenMsgs $folder]
  636.     if {[llength $unseen] > 0} {
  637.     set end [$exwin(ftext) index end]
  638.     set line [lindex [split $end .] 0]
  639.     set msgNum 0
  640.     for {} {$line > 0} {incr line -1} {
  641.         set msgNum [Ftoc_MsgNumber $line]
  642.         set i [lsearch $unseen $msgNum]
  643.         if {$i >= 0} {
  644.         $exwin(ftext) tag add unseen $line.0 $line.end
  645.         set unseen [lreplace $unseen $i $i]
  646.         if {[llength $unseen] == 0} {
  647.             return 1
  648.         }
  649.         }
  650.     }
  651.     # Repair bogus unseen sequences
  652.     # msgNum is the smallest message number, but it might not be
  653.     # the first message in the folder because of short scans
  654.     # Anything in the unseen sequence above msgNum is probably wrong
  655.     # and can result from races with the background process
  656.     foreach id $unseen {
  657.         if {$id > $msgNum} {
  658.         Flist_MsgSeen $id
  659.         }
  660.     }
  661.     } else {
  662.     Flist_SeenAll $folder    ;# clear highlighting
  663.     return 0
  664.     }
  665. }
  666. proc Ftoc_MarkSeen { ids } {
  667.     global exwin ftoc
  668.  
  669.     set ids [lsort -integer -decreasing $ids]
  670.     for {set L $ftoc(numMsgs)} {$L > 0} {incr L -1} {
  671.     set ix [lsearch $ids [Ftoc_MsgNumber $L]]
  672.     if {$ix >= 0} {
  673.         $exwin(ftext) tag remove unseen $L.0 $L.end
  674.         set ids [lreplace $ids $ix $ix]
  675.         if {[llength $ids] == 0} {
  676.         break
  677.         }
  678.     }
  679.     }
  680. }
  681. proc Ftoc_RescanLine { ix {plus none} } {
  682.     global exmh exwin ftoc
  683.     if [catch {
  684.     set text [$exwin(ftext) get ${ix}.0 ${ix}.end]
  685.     set ok 0
  686.     case $plus {
  687.         "none" {
  688.         # Replace + (current marker) with blank
  689.         set ok [regsub {^( *[0-9]+)(\+)} $text {\1 } newtext]
  690.         }
  691.         "+" {
  692.         # Stick a + after the number, if needed
  693.         if ![regexp {^( *)([0-9]+)(\+)} $text] {
  694.             set ok [regsub {^( *[0-9]+)( )} $text {\1+} newtext]
  695.         }
  696.         }
  697.         "dash" {
  698.         # Stick a - after the number, if needed
  699.         if ![regexp {^( *)([0-9]+).-} $text] {
  700.             set ok [regsub {^( *[0-9]+.)(.)} $text {\1-} newtext]
  701.         }
  702.         # Annotations result in writes to the directory.
  703.         # Here we mark the display dirty to force an update
  704.         # of the cache and prevent later rescans.
  705.         set ftoc(displayDirty) 1
  706.         }
  707.     }
  708.     if {$ok} {
  709.         set tags [$exwin(ftext) tag names ${ix}.0]
  710.         $exwin(ftext) configure -state normal
  711.         $exwin(ftext) delete ${ix}.0 ${ix}.end
  712.         $exwin(ftext) insert ${ix}.0 $newtext
  713.         $exwin(ftext) configure -state disabled
  714.         foreach tag $tags {
  715.         $exwin(ftext) tag add $tag ${ix}.0 ${ix}.end
  716.         }
  717.     }
  718.     } msg] {
  719.     Exmh_Error "FtocRescanLine $ix : $msg"
  720.     }
  721. }
  722. proc Ftoc_NextImplied { {show show} {implied implied} } {
  723.     global ftoc
  724.     if {$ftoc(implied) && $ftoc(direction) == "prev"} {
  725.     Ftoc_Prev $show
  726.     } else {
  727.     Ftoc_Next $show $implied
  728.     }
  729. }
  730. proc Ftoc_Next { show {implied no} } {
  731.     # Go to the next message in the scan display
  732.     global exmh flist ftoc
  733.  
  734.     set ftoc(direction) "next"
  735.     if {$ftoc(curLine) == {}} {
  736.     if [Msg_ShowUnseen] {
  737.         return
  738.     }
  739.     }
  740.     set next [FtocSkipMarked $ftoc(curLine) 1]
  741.     if {($ftoc(curLine) == $next) || \
  742.     ($ftoc(curLine) >= $ftoc(numMsgs)) || \
  743.     ($ftoc(curLine) <= 0)} {
  744.     # End of folder
  745.     Ftoc_NextFolder $implied
  746.     } else {
  747.     # Simple case - go to the next message.
  748.     Msg_Pick $next $show
  749.     }
  750. }
  751. proc Ftoc_Prev { {show show} } {
  752.     global ftoc
  753.  
  754.     Exmh_Debug Ftoc_Prev
  755.     if {$ftoc(curLine) == {}} {
  756.     if {$ftoc(numMsgs) > 0} {
  757.         Msg_Pick $ftoc(numMsgs) $show
  758.     }
  759.     return
  760.     }
  761.     if {$ftoc(curLine) > 1} then {
  762.     set ftoc(direction) "prev"
  763.     Msg_Pick [FtocSkipMarked $ftoc(curLine) -1] $show
  764.     } else {
  765.     Ftoc_Next $show implied
  766.     }
  767. }
  768. proc Ftoc_NextFolder { {implied no} } {
  769.     global ftoc exmh
  770.     # Try to chain to the next folder with unread messages.
  771.     if {$implied != "no"} {
  772.     # Implied - chained with some other operation - be lenient
  773.     if {$ftoc(changed) > 0} {
  774.         # Dirty folder - do not change.
  775.         # If on last message, clear display because the
  776.         # message is moved or deleted
  777.         if {$ftoc(curLine) != {}} {
  778.         Ftoc_ClearCurrent
  779.         Msg_ClearCurrent
  780.         }
  781.         Exmh_Status ""
  782.         Exmh_Status "Changes pending; End of folder" warn
  783.         return
  784.     }
  785.     }
  786.     set f [Flist_NextUnseen]
  787.     if {[string length $f] != 0} {
  788.     if {$ftoc(softChange)} {
  789.         set ftoc(lastFolder) $exmh(folder)
  790.         Folder_Change $f Msg_ShowUnseen
  791.         return
  792.     } else {
  793.         set ftoc(softChange) 1
  794.         Ftoc_ClearCurrent
  795.         Msg_ClearCurrent
  796.         Exmh_Status ""
  797.         Exmh_Status "End of folder; <Next> => $f" warn
  798.         return
  799.     }
  800.     }
  801.     Exmh_Status ""
  802.     Exmh_Status "End of folder" warn
  803. }
  804. proc Ftoc_LastFolder {} {
  805.     global ftoc
  806.     if {[info exist ftoc(lastFolder)]} {
  807.     return $ftoc(lastFolder)
  808.     } else {
  809.     return ""
  810.     }
  811. }
  812. proc Ftoc_PrevMarked { {show show} } {
  813.     global ftoc
  814.     set skip $ftoc(skipMarked)
  815.     set ftoc(skipMarked) 0
  816.     Ftoc_Prev $show
  817.     set ftoc(skipMarked) $skip
  818. }
  819. proc Ftoc_Marked { id } {
  820.     global ftoc exwin
  821.     if {$ftoc(skipMarked) == 0} {
  822.     return 0    ;# Pretend it isn't marked
  823.     }
  824.     set i [Ftoc_FindMsg $id]
  825.     if {[string length $i] == 0} {
  826.     return 1    ;# Can't find it, pretend it's marked
  827.     }
  828.     set marked 0
  829.     foreach tag [$exwin(ftext) tag names $i.0] {
  830.     if [regexp {(deleted|moved|drange|mrange)} $tag] {
  831.         set marked 1 ; break;
  832.     }
  833.     }
  834.     return $marked
  835. }
  836. proc FtocSkipMarked {start inc} {
  837.     global exwin ftoc
  838.  
  839.     if {$start == {}} {
  840.     return {}
  841.     }
  842.     for {set i [expr $start+$inc]} {$i > 0 && $i <= $ftoc(numMsgs)} {incr i $inc} {
  843.     if {$ftoc(skipMarked) == 0} {
  844.         return $i
  845.     }
  846.     set marked 0
  847.     foreach tag [$exwin(ftext) tag names $i.0] {
  848.         if [regexp {(deleted|moved|drange|mrange)} $tag] {
  849.         set marked 1 ; break;
  850.         }
  851.     }
  852.     if {! $marked} {
  853.         return $i
  854.     }
  855.     }
  856.     return $start
  857. }
  858.  
  859. proc Ftoc_Changes {type {allowAuto 1} } {
  860.     global ftoc
  861.  
  862.     if {$ftoc(changed) != 0} then {
  863.     Exmh_Debug Ftoc_Changes $type
  864.     if {("$allowAuto" == "1") && $ftoc(autoCommit)} {
  865.         Folder_CommitType $type
  866.         return 0
  867.     }
  868.     if {$type != {}} {
  869.         if {[string compare $type iconified] == 0} {
  870.         set msg "$ftoc(changed) changes pending"
  871.         } else {
  872.         if {$ftoc(commitDialog) &&
  873.             [FtocDialog $ftoc(changed) $type]} {
  874.             Folder_CommitType $type
  875.             Exmh_Focus
  876.             return 0
  877.         } else {
  878.             set msg "$ftoc(changed) changes pending: $type cancelled"
  879.         }
  880.         }
  881.         Exmh_Focus
  882.         Exmh_Status $msg warn
  883.         Sound_Error
  884.     } else {
  885.         Exmh_Status "Oops, $ftoc(changed) left over changes" error
  886.         set ftoc(changed) 0
  887.         return 1
  888.     }
  889.     } else {
  890.     Msg_CheckPoint        ;# Sync unseen and cur message state.
  891.     }
  892.     return $ftoc(changed)
  893. }
  894. proc FtocDialog { changes type } {
  895.     global exwin ftoc
  896.     if [winfo exists $exwin(mtext).commit] {
  897.     destroy $exwin(mtext).commit
  898.     }
  899.     set f [frame $exwin(mtext).commit -class Dialog -bd 4 -relief ridge]
  900.     set blurb [expr {($changes > 1) ? "are $changes changes" : "is one change"}]
  901.     Widget_Message $f msg -text \
  902. "There $blurb pending.
  903. (Press Return to Commit)
  904. (Press <Control-c> to Cancel)" -aspect 1000
  905.     set but [Widget_Frame $f but Dialog {top expand fill} -bd 10]
  906.     set ftoc(okToCommit) 0
  907.     Widget_AddBut $but cancel "Cancel" {set ftoc(okToCommit) 0}
  908.     Widget_AddBut $but ok "Commit and $type" {set ftoc(okToCommit) 1}
  909.     focus $but
  910.     bind $but <Return> "$but.ok flash ; $but.ok invoke"
  911.     bind $but <KP_Enter> "$but.ok flash ; $but.ok invoke"
  912.     bind $but <Control-c> "$but.cancel flash ; $but.cancel invoke"
  913.     Widget_PlaceDialog $exwin(mtext) $exwin(mtext).commit
  914.     Visibility_Wait $but
  915.     catch {grab $but}
  916.     tkwait variable ftoc(okToCommit)
  917.     catch {grab release $but}
  918.     destroy $exwin(mtext).commit
  919.     return $ftoc(okToCommit)
  920. }
  921.  
  922. proc Ftoc_Iterate { lineVar body } {
  923.     global ftoc
  924.     upvar $lineVar line
  925.     catch {
  926.     if {$ftoc(pickone)} {
  927.         if {$ftoc(curLine) != {}} {
  928.         set line $ftoc(curLine)
  929.         uplevel 1 $body
  930.         }
  931.     } else {
  932.         foreach line $ftoc(lineset) {
  933.         uplevel 1 $body
  934.         }
  935.     }
  936.     }
  937. }
  938. proc Ftoc_Unmark {} {
  939.     global ftoc
  940.  
  941.     set hits 0
  942.     Ftoc_Iterate line {
  943.     if [FtocUnmarkInner $line] { incr hits }
  944.     }
  945.     Exmh_Status "Unmarked $hits msgs"
  946.     incr ftoc(changed) -$hits
  947. }
  948. proc FtocUnmarkInner { line {all 0}} {
  949.     global exwin
  950.     set res 0
  951.     if {$all} {
  952.     set pat (deleted|moved|drange|mrange|copied)
  953.     } else {
  954.     set pat (deleted|moved|drange|mrange)
  955.     }
  956.     foreach tag [$exwin(ftext) tag names $line.0] {
  957.     if [regexp $pat $tag] {
  958.         $exwin(ftext) tag remove $tag $line.0 $line.end
  959.         if [regexp {(drange|mrange|crange)} $tag] {
  960.         eval $exwin(ftext) tag add range $line.0 $line.end
  961.         }
  962.         set res 1
  963.     }
  964.     }
  965.     return $res
  966. }
  967. proc Ftoc_Delete { line msgid } {
  968.     global exwin ftoc
  969.     $exwin(ftext) configure -state normal
  970.     $exwin(ftext) delete $line.0 "$line.end + 1 chars"
  971.     $exwin(ftext) configure -state disabled
  972.     set ftoc(displayDirty) 1
  973. }
  974. proc Ftoc_RemoveMark { line msgid } {
  975.     # Flag the current message(s) for deletion
  976.     global ftoc exwin
  977.     if ![FtocUnmarkInner $line 1] {
  978.     incr ftoc(changed)
  979.     }
  980.  
  981.     if {$ftoc(pickone)} {
  982.     $exwin(ftext) tag add deleted $line.0 $line.end
  983.     } else {
  984.     $exwin(ftext) tag remove range $line.0 $line.end
  985.     $exwin(ftext) tag add drange $line.0 $line.end
  986.     }
  987. }
  988. proc Ftoc_MoveMark { line msgid } {
  989.     global ftoc exwin exmh
  990.     if ![FtocUnmarkInner $line] {
  991.     incr ftoc(changed)
  992.     }
  993.     # This tag records the target folder
  994.     $exwin(ftext) tag add [list moved $exmh(target)] $line.0 $line.end
  995.  
  996.     if {$ftoc(pickone)} {
  997.     $exwin(ftext) tag add moved $line.0 $line.end
  998.     } else {
  999.     $exwin(ftext) tag remove range $line.0 $line.end
  1000.     $exwin(ftext) tag add mrange $line.0 $line.end
  1001.     }
  1002. }
  1003. proc Ftoc_CopyMark { line msgid } {
  1004.     global ftoc exwin exmh
  1005.     if ![FtocUnmarkInner $line] {
  1006.     incr ftoc(changed)
  1007.     }
  1008.     # This tag records the target folder
  1009.     $exwin(ftext) tag add [list copied $exmh(target)] $line.0 $line.end
  1010.  
  1011.     if {$ftoc(pickone)} {
  1012.     $exwin(ftext) tag add moved $line.0 $line.end
  1013.     } else {
  1014.     $exwin(ftext) tag remove range $line.0 $line.end
  1015.     $exwin(ftext) tag add mrange $line.0 $line.end
  1016.     }
  1017. }
  1018. proc Ftoc_Commit { rmmCommit moveCommit copyCommit } {
  1019.     global ftoc exwin
  1020.  
  1021.     # Disable operations on ranges
  1022.     Ftoc_RangeUnHighlight
  1023.     if {! $ftoc(pickone)} {
  1024.     Buttons_Range 0
  1025.     set ftoc(lineset) {}
  1026.     set ftoc(pickone) 1
  1027.     }
  1028.  
  1029.     Exmh_Status "Committing $ftoc(changed) changes..."
  1030.     $exwin(ftext) configure -state normal
  1031.     FtocCommit deleted $rmmCommit
  1032.     FtocCommit moved $moveCommit $copyCommit
  1033.     $exwin(ftext) configure -state disabled
  1034.     set l $ftoc(curLine)
  1035.     if {$l == {}} {
  1036.     set l $ftoc(numMsgs)
  1037.     }
  1038.     if {$l > 0} {
  1039.     WidgetTextYview $exwin(ftext) $l
  1040.     }
  1041.     if {! [Ftoc_Changes {} noautocommit]} {
  1042.     Exmh_Status "ok"
  1043.     }
  1044. }
  1045. proc FtocCommit {tagname commitProc {copyCommitProc {}} } {
  1046.     global ftoc exmh exwin msg
  1047.  
  1048.     set delmsgs {}
  1049.     set curid [file tail $msg(path)]
  1050.     set pairs [FtocMakeReversePairs [$exwin(ftext) tag ranges $tagname]]
  1051.     foreach range $pairs {
  1052.     set c0 [lindex $range 0]
  1053.     set ce [lindex $range 1]
  1054.     scan $c0 "%d" L
  1055.     set msgid [Ftoc_MsgNumber $L]
  1056.     set F {}
  1057.     set delline 0    ;# Nuke display line
  1058.     foreach tag [$exwin(ftext) tag names $c0] {
  1059.         if {([llength $tag] == 2) && ([lindex $tag 0] == "moved")} {
  1060.         set F [lindex $tag 1]
  1061.         # Build up a list of moved messages
  1062.         # Note that the original order of the messages is maintained,
  1063.         # (We are going from bottom to top thru the display.)
  1064.         # The scan lines are reversed, which is handled by Scan_Move.
  1065.         if ![info exists movemsgs($F)] {
  1066.             set movemsgs($F) $msgid
  1067.         } else {
  1068.             set movemsgs($F) [concat $msgid " " $movemsgs($F)]
  1069.         }
  1070.         lappend movescan($F) [$exwin(ftext) get $c0 "$ce + 1 chars"]
  1071.         set delline 1
  1072.         }
  1073.         if {([llength $tag] == 2) && ([lindex $tag 0] == "copied")} {
  1074.         set F [lindex $tag 1]
  1075.         # Build up a list of moved messages
  1076.         # Note that the original order of the messages is maintained,
  1077.         # (We are going from bottom to top thru the display.)
  1078.         # The scan lines are reversed, which is handled by Scan_Move.
  1079.         if ![info exists copymsgs($F)] {
  1080.             set copymsgs($F) $msgid
  1081.         } else {
  1082.             set copymsgs($F) [concat $msgid " " $copymsgs($F)]
  1083.         }
  1084.         lappend movescan($F) [$exwin(ftext) get $c0 "$ce + 1 chars"]
  1085.         }
  1086.     }
  1087.     if {$tagname == "deleted"} {
  1088.         # Batch up deletes
  1089.         lappend delmsgs $msgid
  1090.         set delline 1
  1091.     }
  1092.     Flist_MsgSeen $msgid    ;# in case deleted or moved w/out viewing
  1093.     if {$delline} {
  1094.         Msg_UnSeen $msgid    ;# avoid MH mark bug
  1095.         $exwin(ftext) delete $c0 "$ce + 1 chars"
  1096.         set ftoc(displayDirty) 1
  1097.         if {$msgid == $curid} {
  1098.         Ftoc_ClearCurrent
  1099.         Msg_ClearCurrent
  1100.         }
  1101.         if {$L == $ftoc(curLine)} {
  1102.         set ftoc(curLine) {}
  1103.         } elseif {$ftoc(curLine) != {}} {
  1104.         if {$L < $ftoc(curLine)} {
  1105.             incr ftoc(curLine) -1
  1106.             if {$ftoc(curLine) == 0} {
  1107.             set ftoc(curLine) {}
  1108.             }
  1109.         }
  1110.         }
  1111.         incr ftoc(numMsgs) -1
  1112.     } else {
  1113.         FtocUnmarkInner $L
  1114.     }
  1115.     incr ftoc(changed) -1
  1116.     }
  1117.     if {$delmsgs != {}} {
  1118.     Exmh_Status "$commitProc $delmsgs"
  1119.     if [catch {
  1120.         BgAction "Rmm $exmh(folder)" $commitProc $exmh(folder) $delmsgs
  1121.     } err] {
  1122.         Exmh_Status $err error
  1123.     }
  1124.     }
  1125.     # Do copies before links so you can both move and copy a message.
  1126.     if {[catch {array names copymsgs} flist] == 0} {
  1127.     foreach f $flist {
  1128.         Exmh_Status "Copying to $f, $copymsgs($f)"
  1129.         if [catch {
  1130.         BgAction "Refile $f" $copyCommitProc $exmh(folder) $copymsgs($f) $f
  1131.         } err] {
  1132.         Exmh_Status $err error
  1133.         }
  1134.     }
  1135.     }
  1136.     if {[catch {array names movemsgs} flist] == 0} {
  1137.     foreach f $flist {
  1138.         Exmh_Status "Refiling to $f, $movemsgs($f)"
  1139.         if [catch {
  1140.         BgAction "Refile $f" $commitProc $exmh(folder) $movemsgs($f) $f
  1141.         } err] {
  1142.         Exmh_Status $err error
  1143.         }
  1144.     }
  1145.     }
  1146. }
  1147. proc FtocMakePairs { list } {
  1148.     set result {}
  1149.     for {set i 0} {$i < [expr [llength $list]-1]} {incr i +2} {
  1150.     set first [lindex $list $i]
  1151.     set second [lindex $list [expr $i+1]]
  1152.     lappend result [list $first $second]
  1153.     }
  1154.     if {$result == {}} {
  1155.     return $list
  1156.     } else {
  1157.     return $result
  1158.     }
  1159. }
  1160. proc FtocMakeReversePairs { list } {
  1161.     set result {}
  1162.     for {set i [expr [llength $list]-1]} {$i >= 0} {incr i -2} {
  1163.     set second [lindex $list $i]
  1164.     set first [lindex $list [expr $i-1]]
  1165.     lappend result [list $first $second]
  1166.     }
  1167.     if {$result == {}} {
  1168.     return $list
  1169.     } else {
  1170.     return $result
  1171.     }
  1172. }
  1173.  
  1174. proc Ftoc_MoveFeedback { msgid line } {
  1175.     global exwin ftoc
  1176.     set msg [Exmh_OldStatus]
  1177.     if {[string compare $line "last"] == 0} {
  1178.     set line $ftoc(numMsgs)
  1179.     } elseif {[string compare $line first] == 0} {
  1180.     set line 1
  1181.     }
  1182.     foreach tag [$exwin(ftext) tag names $line.0] {
  1183.     if [regexp {moved (.+)} $tag match folder] {
  1184.         Exmh_Status "$msgid => +$folder"
  1185.         return
  1186.     } elseif [regexp deleted $tag] {
  1187.         Exmh_Status "$msgid Pending Delete"
  1188.         return
  1189.     }
  1190.     }
  1191.     Exmh_Status $msg
  1192. }
  1193. proc Ftoc_FindNext {} {
  1194.     Find_It forw
  1195. }
  1196. proc Ftoc_FindPrev {} {
  1197.     Find_It back
  1198. }
  1199. proc Ftoc_FindAll {string} {
  1200.     global exwin find ftoc
  1201.     if {[string length $string] == 0} {
  1202.     Exmh_Status "No search string" warn
  1203.     return -1
  1204.     }
  1205.     set msgids {}
  1206.     for {set L 1} 1 {incr L} {
  1207.     if [$exwin(ftext) compare $L.end >= end] {
  1208.         break
  1209.     }
  1210.     if [catch {$exwin(ftext) get $L.0 $L.end} text] {
  1211.         break
  1212.     }
  1213.     if [regexp -nocase -- $string $text] {
  1214.         lappend msgids [Ftoc_MsgNumberRaw $text]
  1215.     }
  1216.     }
  1217.     if {[llength $msgids] == 0} {
  1218.     Exmh_Status "No match" warn
  1219.     return 0
  1220.     } else {
  1221.     Ftoc_PickMsgs $msgids 0
  1222.     return 1
  1223.     }
  1224.  
  1225. }
  1226. proc Ftoc_FindMatch {L string} {
  1227.     global exwin ftoc
  1228.     if {$L == $ftoc(lasthit)} {
  1229.     return 0
  1230.     }
  1231.     if [catch {$exwin(ftext) get $L.0 $L.end} text] {
  1232.     return -1    ;# off the end or beginning
  1233.     }
  1234.     if [regexp -nocase -- $string $text] {
  1235.     set ftoc(lasthit) $L
  1236.     Msg_Pick $L show
  1237.     return 1
  1238.     }
  1239.     return 0
  1240. }
  1241. proc Ftoc_Yview {args} {
  1242.     global exwin
  1243.     eval {WidgetTextYview $exwin(ftext)} $args
  1244. }
  1245. proc Ftoc_Advance { advance } {
  1246.     global ftoc
  1247.     if {[string compare $advance "advance?"] == 0} {
  1248.     return $ftoc(linkAdvance)
  1249.     } else {
  1250.     return $advance
  1251.     }
  1252. }
  1253. proc Ftoc_PageUp {} {
  1254.     global exwin
  1255.     Widget_TextPageUp $exwin(ftext)
  1256. }
  1257. proc Ftoc_PageDown {} {
  1258.     global exwin
  1259.     Widget_TextPageDown $exwin(ftext)
  1260. }
  1261.  
  1262. proc Ftoc_Sort {} {
  1263.     global ftoc
  1264.     case $ftoc(autoSortType) {
  1265.     {date} { Folder_Sort -datefield date }
  1266.     {subject} { Folder_Sort -textfield subject }
  1267.     {sender} { Folder_Sort -textfield from }
  1268.     {custom} { eval Folder_Sort $ftoc(autoSortCrit) }
  1269.     }
  1270. }
  1271. proc Ftoc_SelectAll {} {
  1272.     global ftoc
  1273.     FtocRangeStart 1
  1274.     FtocRangeEnd $ftoc(numMsgs)
  1275. }
  1276. proc Ftoc_SelectAllToEnd {} {
  1277.     global ftoc
  1278.     if {$ftoc(curLine) != {}} {
  1279.       FtocRangeStart $ftoc(curLine)
  1280.     } else {
  1281.       if {$ftoc(direction) == "next"} {
  1282.         FtocRangeStart 1
  1283.       } else {
  1284.         FtocRangeStart $ftoc(numMsgs)
  1285.       }
  1286.     }
  1287.     if {$ftoc(direction) == "next"} {
  1288.       FtocRangeEnd $ftoc(numMsgs)
  1289.     } else {
  1290.       FtocRangeEnd 1
  1291.     }
  1292. }
  1293. proc Ftoc_CatchUp {} {
  1294.     global ftoc
  1295.     Ftoc_SelectAll
  1296.     Msg_Remove
  1297.     Folder_Commit
  1298.     Msg_PageOrNext
  1299. }
  1300. proc Ftoc_CatchUpToEnd {} {
  1301.     global ftoc
  1302.     Ftoc_SelectAllToEnd
  1303.     Msg_Remove
  1304.     Folder_Commit
  1305.     Msg_PageOrNext
  1306. }
  1307. #
  1308. # Interface to Drag & Drop
  1309. #
  1310. set ftocDrag(types) {foldermsg}
  1311. set ftocDrag(formats) {string filename}
  1312. set ftocDrag(format,foldermsg) string
  1313. set ftocDrag(format,filename) string
  1314. set ftocDrag(type,string) foldermsg
  1315.  
  1316. # Drag Selected
  1317. proc FtocDragSelectOld {w x y wx wy} {
  1318.     global exmh ftoc
  1319.  
  1320.         set folder $ftoc(folder)
  1321.         if !$ftoc(displayValid) {
  1322.             set folder $exmh(folder)
  1323.         }
  1324.     set line [lindex [split [$w index current] .] 0]
  1325.     set msg [Ftoc_MsgNumber $line]
  1326.     if {$msg == {} || $msg == 0} return
  1327.  
  1328.     # Hand off to Drag code
  1329.     global ftocDrag mhProfile
  1330.     set ftocDrag(source) $w
  1331.     set ftocDrag(data,foldermsg) "+$folder $msg"
  1332.     set ftocDrag(data,filename) $mhProfile(path)/$folder/$msg
  1333.     Drag_Source ftocDrag $x $y
  1334. }
  1335. proc FtocDragSelect {w x y wx wy} {
  1336.     global exmh ftoc ftocDrag mhProfile
  1337.  
  1338.     set folder $ftoc(folder)
  1339.     if !$ftoc(displayValid) {
  1340.         set folder $exmh(folder)
  1341.     }
  1342.     set msgs {}
  1343.     if $ftoc(pickone) {
  1344.     set line [lindex [split [$w index current] .] 0]
  1345.     set msgs [Ftoc_MsgNumber $line]
  1346.     if {$msgs == {} || $msgs == 0} return
  1347.     set ftocDrag(data,filename) $mhProfile(path)/$folder/$msgs
  1348.     } else {
  1349.     foreach line $ftoc(lineset) {
  1350.         set msgid [Ftoc_MsgNumber $line]
  1351.         if {$msgid != {}} {
  1352.         lappend msgs $msgid
  1353.         }
  1354.     }
  1355.         catch {unset ftocDrag(data,filename)}
  1356.     }
  1357.  
  1358.     # Hand off to Drag code
  1359.     set ftocDrag(source) $w
  1360.     set ftocDrag(data,foldermsg) "+$folder $msgs"
  1361.     Drag_Source ftocDrag $x $y
  1362.   }
  1363.  
  1364.